C11にクラスはありませんが、構造体と共用体ならあります。また、列挙体も使うことができますができますが、C++11以降で導入された仕様には対応していません。
タグ名だけで型名にならない
C++では、クラスや列挙体のタグ名だけで型名になりましたが、C11では、明示的に struct, union, または enum を付けなければなりません。それが嫌なら、typedef 名を定義する必要があります。
0 1 2 3 4 5 |
struct A { int a; }; A x; /* エラー */ struct A x; /* OK */ |
クラス有効範囲のようなものはない
C++では、クラスの中でクラスを定義した場合、入れ子になったクラスは、外側のクラスのクラス有効範囲に属します。しかし、C11ではクラス有効範囲という概念がないため、このようなことはありません。
0 1 2 3 4 5 6 7 8 9 10 |
struct A { struct B { int value; } b; } a; struct B x; /* OK */ |
構造体や共用体の中で型定義はできない
C11にはクラス有効範囲がありませんので、構造体や共用体の中で型定義を行うことができません。
0 1 2 3 4 5 6 7 8 9 |
struct A { typedef int int_t; /* エラー */ struct B { int b; }; /* エラー */ enum { c, d }; /* エラー */ int a; }; |
集成体
C11では、「集成体」という用語は構造体と配列の総称です。共用体は集成体ではありません
構造体のメモリ配置
構造体型のオブジェクトへのポインタは、そのオブジェクトの最初のメンバへのポインタと同じアドレスをさします。また、構造体のメンバは上から順に、メモリの下位→上位の順に配置されます。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <assert.h> struct A { int a; double b; }; int main(void) { struct A x; assert(&x == (struct A*)&x.a); /* OK */ return 0; } |
構造体や共用体のメンバは必須
C11では、メンバのない構造体や共用体を定義することはできません。
フレキシブル配列メンバ
C11では、二つ以上の名前付きメンバを持つ構造体の最後のメンバとして、フレキシブル配列メンバを使うことができます。フレキシブル配列メンバというのは、不完全配列型のメンバのことです。
0 1 2 3 4 5 6 |
struct foo { int a; char b[]; }; |
フレキシブル配列メンバを使えば、構造体の末尾に可変長の配列をつなげることが容易にできるようになります。
0 1 2 3 4 |
char str[] = "This is a pen."; struct foo *ptr = malloc(sizeof(struct foo) + sizeof str); strcpy(ptr->b, str); |
ビットフィールド
C11では、ビットフィールドの型として使えるのは、_Bool, int, signed int, およびunsigned intだけです。signedもunsignedも付かない単なるintの場合、符号付きか符号無しかは、C++と同様、処理系定義です。
無名構造体と無名共用体
C11では無名構造体や無名共用体を使うことができます。
0 1 2 3 4 5 6 7 8 9 10 11 12 |
int main(void) { struct A { struct B { int y; }; } x; x.y = 123; // OK } |
上記のように入れ子になった構造体や共用体はメンバ名を省略してもメンバとして扱うことができます。C++でこのような書き方をすれば、クラス有効範囲で定義した構造体や共用体になるためまったく別の意味になります。
ところで、C++にも無名共用体がありますが別の仕様なので要注意です。
列挙体
列挙定数はint型
C11は、列挙定数は常にint型になります。列挙体型は処理系定義の整数型になり、基底の整数型を指定することはできません。
有効範囲を持つ列挙型は使えない
C++11以降では有効範囲を持つ列挙体は使うことができません。
0 1 2 3 4 5 6 |
enum class A // エラー { foo, bar }; |
列挙体型の先行宣言は行えない
C++11以降では構造体や共用体と同じように列挙体型の先行宣言を行うことができますが、C11ではエラーになります。
0 1 2 3 4 5 6 7 8 |
enum A; // エラー enum A { foo, bar }; |
式中での型定義
C11では、式や関数の仮引数並びで型定義を行うことができます。具体的には、次のようなことができます。
0 1 2 |
a = ((struct { int a; double b; }*)ptr)->b; |